/* 
 * Copyright (c) 2004-2005 Massachusetts Institute of Technology. This code was
 * developed as part of the Haystack (http://haystack.lcs.mit.edu/) research 
 * project at MIT. Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files (the 
 * "Software"), to deal in the Software without restriction, including without 
 * limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 */

/*
 * Created on Mar 29, 2006
 */
package edu.mit.csail.relo.parts;

import org.apache.log4j.Logger;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;

import edu.mit.csail.relo.ReloCore;
import edu.mit.csail.relo.ReloPlugin;
import edu.mit.csail.relo.commands.AddNodeAndRelCmd;
import edu.mit.csail.relo.modelBridge.DirectedRel;
import edu.mit.csail.relo.parts.NavAidsEditPolicy.BasicRootController;
import edu.mit.csail.relo.parts.NavAidsEditPolicy.NavAidsEditPart;
import edu.mit.csail.relo.parts.NavAidsEditPolicy.NavAidsRelEditPart;
import edu.mit.csail.relo.store.StoreUtil;

public abstract class NavAidsSpec {
    static final Logger logger = ReloPlugin.getLogger(NavAidsSpec.class);

    public NavAidsEditPolicy navAidsPolicy = null;
    public IFigure decorationFig = null;

    protected IFigure getReqButton(final EditPart hostEP, String iconName, String reqType, String tooltip) {
        Request req = new Request(reqType);
        final Command cmd = hostEP.getCommand(req);
        if (cmd == null) return null;

        IFigure lbl = new Label(NavAidsEditPolicy.getIconImage(iconName));
        IFigure btn = navAidsPolicy.getButton(lbl, cmd, /*rightClickMenu*/ null, tooltip);
        btn.setToolTip(new Label(" " + tooltip + " "));
        return btn;
    }

    protected IFigure getRelation(EditPart hostEP, DirectedRel rel) {
        NavAidsEditPart aep = (NavAidsEditPart) hostEP;
        int relCnt = directRelationCnt(aep, rel);
        if (relCnt == 0) return null;
        
        return getRelation(aep, rel, relCnt);
    }
    // call with relCnt = -1 if count is not available and you still want the relation to show 
    protected IFigure getRelation(NavAidsEditPart aep, final DirectedRel rel, int relCnt) {
        NavAidsRelEditPart relInst = (NavAidsRelEditPart) StoreUtil.loadClass(aep.getRepo(), rel.res, ReloCore.controller);
        if (relInst == null) {
        	logger.error("Not able to load AREP class for : " + rel.res, new Exception());
        	return null;
        }
        IFigure arrow = relInst.getArrow();
        if (relCnt != -1)
            arrow.setToolTip(new Label(" " + relInst.getRelationLabel(aep.getRepo(), rel.res) + " (" + relCnt + " items) "));

        CompoundCommand btnExecCmd = new CompoundCommand();
        aep.showAllDirectRelation(btnExecCmd, rel, null);
        if (btnExecCmd.size() == 0) return null;
        
        ContextMenuProvider rightClickMenuBuilder = getRelationContextMenu(aep, rel);
        IFigure btn = navAidsPolicy.getButton(arrow, btnExecCmd.unwrap(), rightClickMenuBuilder, null);
        return btn;
    }

    private int directRelationCnt(NavAidsEditPart aep, DirectedRel prop) {
        BasicRootController rc = aep.getRootController();
        int relCnt = 0;
        for (Object relArt : aep.listModel(aep.getRepo(), prop, null)) {
            if (rc.findEditPart(relArt) == null && rc.modelCreatable(relArt))
                relCnt++;
        }
        return relCnt;
    }


    private ContextMenuProvider getRelationContextMenu(final NavAidsEditPart aep, final DirectedRel rel) {
        return new ContextMenuProvider(aep.getViewer()) {
            @Override
            public void buildContextMenu(IMenuManager menuManager) {
                final BasicRootController rc = aep.getRootController();
                IContributionItem[] contributions = this.getItems();
                if (contributions.length > 0)
                	menuManager.add(new Separator("header"));
                for (IContributionItem menuItem : contributions) {
                	menuManager.add(menuItem);
                }
                menuManager.add(new Separator("main"));
                for (final Object relArt : aep.listModel(aep.getRepo(), rel, null)) {
                    if (rc.findEditPart(relArt) != null) continue;
                    if (!rc.modelCreatable(relArt)) continue;
                    String relArtLbl = aep.getRelModelLabel(relArt);
                    
                    IAction action = new Action(relArtLbl) {
                        @Override
                        public void run() {
                            rc.execute(new AddNodeAndRelCmd(rc, aep, rel.res, relArt, rel.isFwd));
                        }
                    };
                    
                    try {
                        ImageDescriptor des = rc.getIconDescriptor(aep, relArt);
                        if (des != null) action.setImageDescriptor(des);
                    } catch (Throwable t) {
                        NavAidsEditPolicy.logger.error("Unexpected error while getting icon for: " + relArt, t);
                    }
                    menuManager.appendToGroup("main", action);
                }

            }
        };
    }

    // actually build the decoration figure
    abstract public void buildHandles();
    
    // would like to have a nice set of alignment operators for use here 
    abstract public Point getHandlesPosition(IFigure containerFig);
}